package fr.norsys.mapper.console.service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LDAPViewerImpl implements LDAPViewer {
	private final static Log log = LogFactory.getLog(LDAPViewerImpl.class);

	private DirContext context;

	public DirContext getContext() {
		return context;
	}

	public void setContext(DirContext context) {
		this.context = context;
	}

	public Set getAllAttributes(String root) {
		Set res = new TreeSet();
		List objectClasses = getObjectClasses(root);
		try {
			DirContext schema = context.getSchema("");
			for (Iterator i = objectClasses.iterator(); i.hasNext();) {
				String oc = (String) i.next();
				Attributes ocAttrs = schema.getAttributes("ClassDefinition/"
						+ oc);
				if (ocAttrs != null) {
					Attribute must = ocAttrs.get("MUST");
					Attribute may = ocAttrs.get("MAY");
					if (must != null) {
						NamingEnumeration e = must.getAll();
						while (e.hasMore()) {
							String attr = (String) e.next();
							if (attr != null) {
								res.add(attr);
							}
						}
					}
					if (may != null) {
						NamingEnumeration e = may.getAll();
						while (e.hasMore()) {
							String attr = (String) e.next();
							if (attr != null) {
								res.add(attr);
							}
						}
					}
				}
			}
		} catch (NamingException e) {
			log.error(e);
		}
		return res;
	}

	public List getObjectClasses(String root) {
		List res = new ArrayList();
		SearchControls controls = new SearchControls();
		String[] rAttr = { "objectclass" };
		controls.setSearchScope(1);
		controls.setDerefLinkFlag(false);
		controls.setReturningObjFlag(false);
		controls.setReturningAttributes(rAttr);
		try {
			NamingEnumeration e = context.search(root, "(objectclass=*)",
					controls);
			while (e.hasMore()) {
				SearchResult s = (SearchResult) e.next();
				NamingEnumeration attrs = s.getAttributes().getAll();
				while (attrs.hasMore()) {
					Attribute attr = (Attribute) attrs.next();
					if (attr.getID().equalsIgnoreCase("objectclass")) {
						NamingEnumeration e2 = attr.getAll();
						while (e2.hasMore()) {
							res.add(e2.next());
						}
					}
				}
			}
		} catch (NamingException e) {
			log.error(e);
		}
		return res;
	}

	public Set getMandatoryAttributes(String root) {
		return getAttributes(context, root, "MUST");
	}

	public Set getAttributes(DirContext ctx, String search, String type) {
		Set res = null;
		List objectClasses = getObjectClasses(search);
		if (!objectClasses.isEmpty()) {
			res = new TreeSet();
			try {
				DirContext schema = ctx.getSchema("");
				for (Iterator i = objectClasses.iterator(); i.hasNext();) {
					String oc = (String) i.next();
					Attributes ocAttrs = schema
							.getAttributes("ClassDefinition/" + oc);
					if (ocAttrs != null) {
						Attribute option = ocAttrs.get(type);
						if (option != null) {
							NamingEnumeration e = option.getAll();
							while (e.hasMore()) {
								String attr = (String) e.next();
								if (attr != null) {
									res.add(attr);
								}
							}
						}
					}
				}
			} catch (NamingException e) {
				log.error(e);
			}
		}
		return res;
	}

	public Set getOptionalAttributes(String root) {
		return getAttributes(context, root, "MAY");
	}

	public List getChildElements(String root) {
		List res = new ArrayList();
		SearchControls controls = new SearchControls();
		String[] rAttr = { "ou", "o" };
		controls.setSearchScope(1);
		controls.setReturningAttributes(rAttr);
		try {
			NamingEnumeration e = context.search(root, "(objectclass=*)",
					controls);
			while (e.hasMore()) {
				SearchResult s = (SearchResult) e.next();
				NamingEnumeration attrs = s.getAttributes().getAll();
				while (attrs.hasMore()) {
					Attribute attr = (Attribute) attrs.next();
					String id = attr.getID();
					NamingEnumeration e2 = attr.getAll();
					while (e2.hasMore()) {
						res.add(id + "=" + e2.next());
					}
				}
			}
		} catch (NamingException e) {
			log.error(e);
		}
		return res;
	}
}
